using System;
using System.Runtime.Serialization;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Messaging;

using Pegasus.Diagnostics;

namespace Pegasus.Runtime.Remoting.Messaging
{
	/// <summary>
	/// This hold the custom surrogates for the remoting in the pegasus library.  We had to use this because the
	/// .NET System object are marked as internal and unaccessable to us.
	/// </summary>
	internal class PegasusRemotingSurrogateSelector : ISurrogateSelector
	{
		// Local Instance Values
		private ISurrogateSelector m_nextSelector = null;

		/// <summary>
		/// Initializes a new instance of the <see cref="PegasusRemotingSurrogateSelector"/> class.
		/// </summary>
		internal PegasusRemotingSurrogateSelector()
		{
			m_nextSelector = new RemotingSurrogateSelector();
		}

		/// <summary>
		/// Specifies the next <see cref="T:System.Runtime.Serialization.ISurrogateSelector"></see> for surrogates to examine if the current instance does not have a surrogate for the specified type and assembly in the specified context.
		/// </summary>
		/// <param name="selector">The next surrogate selector to examine.</param>
		/// <exception cref="T:System.Security.SecurityException">The caller does not have the required permission. </exception>
		public void ChainSelector( ISurrogateSelector selector )
		{
			m_nextSelector = selector;
		}

		/// <summary>
		/// Returns the next surrogate selector in the chain.
		/// </summary>
		/// <returns>
		/// The next surrogate selector in the chain or null.
		/// </returns>
		/// <exception cref="T:System.Security.SecurityException">The caller does not have the required permission. </exception>
		public ISurrogateSelector GetNextSelector()
		{
			return m_nextSelector;
		}

		/// <summary>
		/// Finds the surrogate that represents the specified object's type, starting with the specified surrogate selector for the specified serialization context.
		/// </summary>
		/// <param name="type">The <see cref="T:System.Type"></see> of object (class) that needs a surrogate.</param>
		/// <param name="context">The source or destination context for the current serialization.</param>
		/// <param name="selector">When this method returns, contains a <see cref="T:System.Runtime.Serialization.ISurrogateSelector"></see> that holds a reference to the surrogate selector where the appropriate surrogate was found. This parameter is passed uninitialized.</param>
		/// <returns>
		/// The appropriate surrogate for the given type in the given context.
		/// </returns>
		/// <exception cref="T:System.Security.SecurityException">The caller does not have the required permission. </exception>
		public ISerializationSurrogate GetSurrogate( Type type, StreamingContext context, out ISurrogateSelector selector )
		{
			// Check Parameters
			ParamCode.AssertNotNull( type, "type" );
			
			// Initialize out parameters
			selector = null;

			// If it's our method call object then just return
			if( typeof( PegasusMethodCall ) != type )
			{
				// Call the remote selector to process any ref objects
				if( m_nextSelector != null )
				{
					return m_nextSelector.GetSurrogate( type, context, out selector );
				}
			}

			return null;
		}
	}
}
